home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / sound / dsond131.zip / DSOUND.C < prev    next >
C/C++ Source or Header  |  1994-03-06  |  23KB  |  845 lines

  1.  
  2. /**************************************************************************/
  3. /*                 DSound V1.31                  */
  4. /*     Copyright 1991-1994 by Dave Schreiber, All Rights Reserved      */
  5. /*                                      */
  6. /* To compile with SAS/C version 6, type:                  */
  7. /*    smake                                  */
  8. /*                                      */
  9. /* Revision history:                              */
  10. /*    V1.31  - Fixed some bugs that caused some samples (esp. ones        */
  11. /*           without a CHAN chunk) to not play.              */
  12. /*           March 6, 1994                          */
  13. /*    V1.30  - DSound now displays the name of the sound sample being      */
  14. /*           played, the number of seconds of the sample that have been */
  15. /*           played, and the total number of seconds in the sample.      */
  16. /*           A bug that prevent DSound from being aborted from the      */
  17. /*           window when a stereo sample is played has also been fixed. */
  18. /*           July 17, 1993                          */
  19. /*    V1.20  - Added the ability to stop DSound by typing CTRL-C, and      */
  20. /*           added the switch '-w', which keeps the DSound window from  */
  21. /*           opening.                           */
  22. /*           August 23, 1992                          */
  23. /*    V1.10  - Added the ability to play a sound sample repeatedly (in a  */
  24. /*           loop).                              */
  25. /*           July 11, 1992                          */
  26. /*    V1.00  - Added a new module (Mem.c) which allows a sample to be     */
  27. /*           loaded entirely into memory, so samples can be played from */
  28. /*           floppy disk without first copying to a hard or RAM drive.  */
  29. /*           DSound also can now play a single channel of a stereo      */
  30. /*           out of two speakers.  The small window, used to let the      */
  31. /*           user abort a playing sample, as been redone (DSound also   */
  32. /*           now responds instantly when the user clicks on the Close   */
  33. /*           gadget).  DSound now checks a given 8SVX sample to make      */
  34. /*           sure that it is actually a valid sample.  Finally, DSound  */
  35. /*           has been made pure (residentiable).                        */
  36. /*           Second release (April 16, 1992)                            */
  37. /*    V0.94a - Can now play a mono sample out of both speakers at the      */
  38. /*           same time (using the -2 switch).                           */
  39. /*           March 27, 1992 (a little later)                            */
  40. /*    V0.93a - Now handles stereo sound samples.  Either the right or      */
  41. /*           left, or both, stereo channels can be played.  Also split  */
  42. /*           off the code that actually plays the sound sample into a   */
  43. /*           separate source file (Play.c).                             */
  44. /*           March 27, 1992                          */
  45. /*    V0.92a - Now gets the length of the sound sample from the head of   */
  46. /*           the BODY chunk, instead of the VHDR (a workaround to a bug */
  47. /*           in the Perfect Sound software that would sometimes store   */
  48. /*           an incorrect length in the VHDR chunk of a sound sample).  */
  49. /*           November 4, 1991                       */
  50. /*    V0.91a - First release (September 11, 1991)                         */
  51. /**************************************************************************/
  52.  
  53. #include <exec/types.h>
  54. #include <exec/exec.h>
  55. #include <devices/audio.h>
  56. #include <dos/dos.h>
  57. #include <intuition/intuition.h>
  58. #include <intuition/intuitionbase.h>
  59. #include <graphics/gfxbase.h>
  60. #include <stdlib.h>
  61. #include <stdio.h>
  62. #include <string.h>
  63.  
  64. #include "dsound.h"
  65.  
  66. #include <proto/intuition.h>
  67. #include <proto/graphics.h>
  68. #include <proto/exec.h>
  69. #include <proto/dos.h>
  70.  
  71. char filename[256];
  72.  
  73. #define DEF_BUF_SIZE 0xFFFFFFFF
  74.  
  75. void InterpretArgs(int argc,char *argv[]);
  76. BOOL noFilter=FALSE;
  77. UBYTE volume=0;
  78. UWORD speed=0;
  79. ULONG bufSize=DEF_BUF_SIZE;
  80.  
  81. void filter_on(void);
  82. void filter_off(void);
  83. char *getDoubleDigit(unsigned int value,char *buf);
  84.  
  85. char *version="$VER: DSound V1.31 (6.3.94)";
  86. char *copyright="Copyright 1991-1992 by Dave Schreiber, All Rights Reserved";
  87.  
  88. struct IntuitionBase *IntuitionBase=NULL;
  89. struct GfxBase *GfxBase=NULL;
  90.  
  91. struct Window *window=NULL;
  92.  
  93. BPTR file=NULL;
  94.  
  95. channel audioChannel=UNSPECIFIED;
  96. BOOL bothChan=FALSE;
  97. BOOL readAll=FALSE;
  98. BOOL loop=FALSE;
  99. BOOL titleBarName=TRUE;
  100. BOOL titleBarTime=TRUE;
  101.  
  102. /*The window definition*/
  103. struct NewWindow newWindow = {
  104.     0,0,
  105.     60,56,
  106.     0,1,
  107.     CLOSEWINDOW,
  108.     SMART_REFRESH|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE,
  109.     NULL,
  110.     NULL,
  111.     "DSound V1.31",
  112.     NULL,
  113.     NULL,
  114.     5,5,
  115.     640,200,
  116.     WBENCHSCREEN
  117. };
  118.  
  119. /*This determines whether or not the window will be opened*/
  120. BOOL openTheWdw=TRUE;
  121. ULONG signalMask=SIGBREAKF_CTRL_C;
  122.  
  123. struct TextFont *titleBarFont=NULL;
  124.  
  125. main(int argc,char *argv[])
  126. {
  127.    struct Voice8Header vhdr;
  128.    UBYTE foo2[5];
  129.    UBYTE foo[5];
  130.    ULONG chan;
  131.    ULONG sampleLength;
  132.    ULONG lock;
  133.    ULONG titleLength,nameLength,timeLength,colonLength,finalDelta;
  134.    char *chanStr;
  135.  
  136.    filename[0]=NULL;
  137.  
  138.    /*Get and interpret the command-line arguments*/
  139.    InterpretArgs(argc,argv);
  140.  
  141.    /*Exit if there was no sound sample specified*/
  142.    if(filename[0]==NULL)
  143.    {
  144.       WriteMsg("Please specify the name of a sound sample\n");
  145.       cleanup(75);
  146.    }
  147.  
  148.    /*Open the file*/
  149.    file=Open(filename,MODE_OLDFILE);
  150.    if(file==NULL)
  151.    {
  152.       WriteMsg("Couldn't open the file\n");
  153.       cleanup(100);
  154.    }
  155.  
  156.    /*If the user hasn't told us not to open the window*/
  157.  
  158.    if(openTheWdw)
  159.    {
  160.       char temp[256];
  161.       /*Open libraries*/
  162.       GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
  163.       IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
  164.  
  165.       if(GfxBase==NULL || IntuitionBase==NULL)
  166.       {
  167.      WriteMsg("A shared library could not be opened\n");
  168.      cleanup(50);
  169.       }
  170.  
  171.       /*Get the size of the title bar font in a rather illegal way        */
  172.       /*Note:  programmers at C= should put a GetDefTitleBarFontHeight()    */
  173.       /*function into Intuition before complaining to me about the following*/
  174.       /*code.                                    */
  175.  
  176.       lock=LockIBase(0L);
  177.       newWindow.Height=IntuitionBase->ActiveScreen->Font->ta_YSize+3;
  178.       UnlockIBase(lock);
  179.  
  180.       window=OpenWindow(&newWindow);
  181.  
  182.       if(window==NULL)
  183.      cleanup(110);
  184.       signalMask|=1<<window->UserPort->mp_SigBit;
  185.  
  186.       titleBarFont=OpenFont(IntuitionBase->ActiveScreen->Font);
  187.       if(titleBarFont==NULL)
  188.      cleanup(115);
  189.  
  190.       SetFont(window->RPort,titleBarFont);
  191.       finalDelta=titleLength=TextLength(window->RPort,"DSound V1.31",12);
  192.       colonLength=TextLength(window->RPort,":  ",3);
  193.       if(titleBarTime==FALSE)
  194.       {
  195.      timeLength=0;
  196.      if(titleBarName==FALSE)
  197.         colonLength=0;
  198.       }
  199.       else
  200.      timeLength=TextLength(window->RPort,"(00:00/00:00) ",14);
  201.  
  202.       if(titleBarName==FALSE)
  203.      nameLength=0;
  204.       else
  205.       {
  206.      strcpy(temp,"\"\"");
  207.      strcat(temp,filename);
  208.      nameLength=TextLength(window->RPort,temp,strlen(temp));
  209.       }
  210.  
  211.       if(60+finalDelta+nameLength+colonLength+timeLength >= window->WScreen->Width)
  212.       {
  213.      titleBarName=FALSE;
  214.      if(60+finalDelta+colonLength+timeLength >= window->WScreen->Width)
  215.      {
  216.         titleBarTime=FALSE;
  217.         if(60+titleLength >= window->WScreen->Width)
  218.            cleanup(199);
  219.      }
  220.      else
  221.         finalDelta+=(colonLength+timeLength);
  222.       }
  223.       else
  224.      finalDelta+=(colonLength+timeLength+nameLength);
  225.  
  226.       SizeWindow(window,finalDelta,0);
  227.    }
  228.  
  229.    /*Read the header*/
  230.    Read(file,foo,4);
  231.    Seek(file,4,OFFSET_CURRENT);
  232.    Read(file,foo2,4);
  233.  
  234.    foo[4]=foo2[4]=NULL;
  235.  
  236.    /*Check the header's validity, more or less*/
  237.    if((strcmp(foo,"FORM")!=0) || (strcmp(foo2,"8SVX")!=0))
  238.    {
  239.       WriteMsg("Not a valid IFF 8SVX sound sample file.\n");
  240.       cleanup(120);
  241.    }
  242.  
  243.    if(strcmp(FindChunk(file,"VHDR"),"VHDR")!=0)
  244.    {
  245.       WriteMsg("Couldn't find the 8SVX header (VHDR).\n");
  246.       cleanup(130);
  247.    }
  248.  
  249.    /*Skip past the chunk size*/
  250.    Seek(file,4,OFFSET_CURRENT);
  251.  
  252.    /*Get the VHDR*/
  253.    Read(file,&vhdr,sizeof(struct Voice8Header));
  254.  
  255.    /*If no buffer size was specified, use a buffer that can hold 1 second*/
  256.    /*of sound*/
  257.    if(bufSize==0xFFFFFFFF)
  258.       bufSize=vhdr.samplesPerSec;
  259.  
  260.    /*Check for compression*/
  261.    if(vhdr.sCompression!=0)
  262.    {
  263.       WriteMsg("Can't play a compressed sample!\n");
  264.       cleanup(400);
  265.    }
  266.  
  267.    /*Get the CHAN chunk (which will tell us if the sample is stereo, or,*/
  268.    /*if it is mono, which speaker it should be played out of*/
  269.    chanStr=FindChunk(file,"CHAN");
  270.    if(strcmp(chanStr,"CHAN")==0)
  271.    {
  272.       /*Skip past chunk size*/
  273.       Seek(file,4,OFFSET_CURRENT);
  274.       Read(file,&chan,sizeof(long));
  275.  
  276.       /*The information we're looking for consists of one longword*/
  277.       switch(chan)
  278.       {
  279.      case 2:  /*Mono sample, left speaker*/
  280.         if(bothChan)
  281.            /*Play out of both channels if -2 used*/
  282.            audioChannel=MONO_BOTH;
  283.         else
  284.            if(audioChannel==UNSPECIFIED)
  285.           audioChannel=MONO_LEFT;
  286.         break;
  287.      case 4:  /*Mono sample, right speaker*/
  288.         if(bothChan)
  289.            /*Play out of both channels if -2 used*/
  290.            audioChannel=MONO_BOTH;
  291.         else
  292.            if(audioChannel==UNSPECIFIED)
  293.           audioChannel=MONO_RIGHT;
  294.         break;
  295.      case 6:     /*Stereo*/
  296.         switch(audioChannel)
  297.         {
  298.            /*This reconciles a user's choice with the fact that the*/
  299.            /*sample is in stereo*/
  300.  
  301.            /*Play left stereo channel*/
  302.            case MONO_LEFT:
  303.           if(bothChan)
  304.              audioChannel=STEREO_LEFT_BOTH;
  305.           else
  306.              audioChannel=STEREO_LEFT;
  307.           break;
  308.  
  309.            /*Play right stereo channel*/
  310.            case MONO_RIGHT:
  311.           if(bothChan)
  312.              audioChannel=STEREO_RIGHT_BOTH;
  313.           else
  314.              audioChannel=STEREO_RIGHT;
  315.           break;
  316.  
  317.            /*Play both channels*/
  318.            case UNSPECIFIED:
  319.           audioChannel=STEREO;
  320.           break;
  321.         }
  322.         break;
  323.       }
  324.    }
  325.    else
  326.    {
  327.       chan=0;
  328.       if(bothChan)
  329.      audioChannel=MONO_BOTH;
  330.    }
  331.  
  332.    /*Find the start of the BODY chunk*/
  333.    chanStr=FindChunk(file,"BODY");
  334.  
  335.    if(strcmp(chanStr,"BODY")!=0)
  336.    {
  337.       WriteMsg("Couldn't find body of sample.\n");
  338.       cleanup(140);
  339.    }
  340.  
  341.    if(noFilter)
  342.       filter_off();
  343.  
  344.    /*Get the length of the sample*/
  345.    Read(file,(char *)&sampleLength,4);
  346.  
  347.    SetSignal(0,0);
  348.  
  349.    /*Play the sample by choosing the appropriate player function*/
  350.    switch(audioChannel)
  351.    {
  352.       case MONO_LEFT:
  353.       case MONO_RIGHT:
  354.       case UNSPECIFIED:
  355.      /*Simple mono playback*/
  356.      playMonoSample(file,audioChannel,&vhdr,sampleLength);
  357.      break;
  358.       case MONO_BOTH:
  359.      /*Mono playback using both speakers*/
  360.      playMonoTwice(file,audioChannel,&vhdr,sampleLength);
  361.      break;
  362.       case STEREO_RIGHT:
  363.      /*Right stereo channel*/
  364.      audioChannel=MONO_RIGHT;
  365.      Seek(file,sampleLength/2,OFFSET_CURRENT);
  366.      playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
  367.      break;
  368.       case STEREO_RIGHT_BOTH:
  369.      /*Right stereo channel out of both speakers*/
  370.      audioChannel=MONO_RIGHT;
  371.      Seek(file,sampleLength/2,OFFSET_CURRENT);
  372.      playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
  373.      break;
  374.       case STEREO_LEFT:
  375.      /*Left stereo channel*/
  376.      audioChannel=MONO_LEFT;
  377.      playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
  378.      break;
  379.       case STEREO_LEFT_BOTH:
  380.      /*Left stereo channel out of both speakers*/
  381.      audioChannel=MONO_LEFT;
  382.      playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
  383.      break;
  384.       case STEREO:
  385.      /*Stereo sample (both channels)*/
  386.      playStereoSample(file,audioChannel,&vhdr,sampleLength/2,filename);
  387.      break;
  388.    }
  389.  
  390.    if(noFilter)
  391.       filter_on();
  392.  
  393.    /*Free allocated resources and exit*/
  394.    cleanup(0);
  395. }
  396.  
  397.  
  398.  
  399. /* Get an audio channel */
  400. struct IOAudio *GetAudioChannel(ULONG bufferSize,UBYTE *allocationMap)
  401. {
  402.    struct IOAudio *aIOB;
  403.    void *audioBuf;
  404.    struct Port *aPort;
  405.  
  406.    aPort=(struct Port *)CreatePort("dsound",0);
  407.    if(aPort==NULL)
  408.       return(NULL);
  409.  
  410.    /* Allocate the chip memory buffer for the channel */
  411.    audioBuf=(void *)AllocMem(bufferSize,MEMF_CHIP);
  412.    if(audioBuf==NULL)
  413.    {
  414.       DeletePort((struct MsgPort *)aPort);
  415.       return(NULL);
  416.    }
  417.  
  418.    /* Allocate an IOAudio structure*/
  419.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  420.    if(aIOB==NULL)
  421.    {
  422.       DeletePort((struct MsgPort *)aPort);
  423.       FreeMem(audioBuf,bufferSize);
  424.       return(NULL);
  425.    }
  426.  
  427.    /* Set up the IOAudio to allocate the command channel */
  428.    aIOB->ioa_Request.io_Message.mn_Node.ln_Pri=0;
  429.    aIOB->ioa_Request.io_Message.mn_ReplyPort=(struct MsgPort *)aPort;
  430.  
  431.    aIOB->ioa_Data=allocationMap;
  432.    aIOB->ioa_Length=4;
  433.    aIOB->ioa_Request.io_Command=ADCMD_ALLOCATE;
  434.  
  435.    /*Open the audio device*/
  436.    OpenDevice("audio.device",0,(struct IORequest *)aIOB,0);
  437.  
  438.  
  439.    if(aIOB->ioa_AllocKey==0)
  440.    {  /*There was an error*/
  441.       DeletePort((struct MsgPort *)aPort);
  442.       FreeMem(audioBuf,bufferSize);
  443.       FreeMem(aIOB,sizeof(struct IOAudio));
  444.       return(NULL);
  445.    }
  446.    else
  447.    {
  448.       /* Set up the IOAudio for writes */
  449.       aIOB->ioa_Request.io_Command=CMD_WRITE;
  450.       aIOB->ioa_Request.io_Flags=ADIOF_PERVOL;
  451.       aIOB->ioa_Data=audioBuf;
  452.       aIOB->ioa_Length=bufferSize;
  453.       return(aIOB);
  454.    }
  455. }
  456.  
  457. /* Free an allocated audio channel */
  458. void FreeAudioChannel(struct IOAudio *aIOB)
  459. {
  460.    if(aIOB==NULL)
  461.       return;
  462.  
  463.    /* Free the audi obuffer */
  464.    if(aIOB->ioa_Data!=NULL)
  465.       FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  466.  
  467.    /* Free the audio channel */
  468.    aIOB->ioa_Request.io_Command=ADCMD_FREE;
  469.    BeginIO((struct IORequest *)aIOB);
  470.    WaitIO((struct IORequest *)aIOB);
  471.    DeletePort(aIOB->ioa_Request.io_Message.mn_ReplyPort);
  472.  
  473.    /* Close the audio channel */
  474.    CloseDevice((struct IORequest *)aIOB);
  475.  
  476.    /* Free the IOAudio structure */
  477.    FreeMem(aIOB,sizeof(struct IOAudio));
  478.    return;
  479. }
  480.  
  481. /* Initialize an IOAudio's volume, period, and set the number of cycles */
  482. /* to one */
  483. void InitAudioChannel(struct IOAudio *aIOB,UWORD volume,UWORD period)
  484. {
  485.    aIOB->ioa_Period=period;
  486.    aIOB->ioa_Volume=volume;
  487.    aIOB->ioa_Cycles=1;
  488.    return;
  489. }
  490.  
  491. /* Duplicate an IOAudio structure */
  492. struct IOAudio *DuplicateAudioChannel(struct IOAudio *OrigIOB)
  493. {
  494.    struct IOAudio *aIOB;
  495.    void *audioBuf;
  496.  
  497.    if(OrigIOB==NULL)
  498.       return(NULL);
  499.  
  500.    /* Allocate the alternate buffer */
  501.    audioBuf=(void *)AllocMem(OrigIOB->ioa_Length,MEMF_CHIP);
  502.    if(audioBuf==NULL)
  503.       return(NULL);
  504.  
  505.    /*Allocate the IOAudio structure*/
  506.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  507.    if(aIOB==NULL)
  508.    {
  509.       FreeMem(audioBuf,OrigIOB->ioa_Length);
  510.       return(NULL);
  511.    }
  512.  
  513.    /*Copy the original IOAudio's contents to the new one*/
  514.    CopyMem(OrigIOB,aIOB,sizeof(struct IOAudio));
  515.  
  516.    /*Except for the buffer pointer, of course*/
  517.    aIOB->ioa_Data=audioBuf;
  518.  
  519.    return(aIOB);
  520. }
  521.  
  522. /*Delete a duplicated IOAudio*/
  523. void DeleteDuplication(struct IOAudio *aIOB)
  524. {
  525.    if(aIOB != NULL)
  526.    {
  527.       /* Free the memory for the buffer and IOAudio */
  528.       if(aIOB->ioa_Data != NULL)
  529.      FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  530.       FreeMem(aIOB,sizeof(struct IOAudio));
  531.    }
  532.    return;
  533. }
  534.  
  535. /* Load an IOAudio's buffer from an open file */
  536. ULONG LoadAudioBuffer(BPTR file,struct IOAudio *aIOB,ULONG toRead)
  537. {
  538.    if(toRead==0)
  539.       return(0);
  540.  
  541.    if(file==0L)
  542.       getLeft(aIOB->ioa_Data);
  543.    else if(file==4L)
  544.       getRight(aIOB->ioa_Data);
  545.    else
  546.       aIOB->ioa_Length=Read(file,aIOB->ioa_Data,toRead);
  547.    return(aIOB->ioa_Length);
  548. }
  549.  
  550. /*Find the beginning of an IFF chunk.  This routine will search for that*/
  551. /*chunk's name, and if found, will leave the file cursor at the chunk size*/
  552. /*field.  If the chunk isn't found, the file cursor will be left at the*/
  553. /*size field of the BODY chunk, if there was one*/
  554. char *FindChunk(BPTR file,char *string)
  555. {
  556.    long len,actLen;
  557.    int origPos;
  558.    static char buf[5];
  559.    buf[4]=NULL;
  560.  
  561.    /* If we cannot find the chunk, seek the file pointer back to the */
  562.    /* place it started at */
  563.    origPos=Seek(file,0,OFFSET_CURRENT);
  564.  
  565.    actLen=Read(file,buf,4);
  566.    while(strcmp(string,buf)!=0 && strcmp(buf,"BODY")!=0 && actLen > 0)
  567.    {
  568.       Read(file,(char *)&len,4);
  569.       len=(len+1) & (~1);
  570.       Seek(file,len,OFFSET_CURRENT);
  571.       actLen=Read(file,buf,4);
  572.    }
  573.    if(strcmp(string,buf)!=0)
  574.       Seek(file,origPos,OFFSET_BEGINNING);
  575.  
  576.    return(buf);
  577. }
  578.  
  579. /* Interpret the command line arguments */
  580. void InterpretArgs(int argc,char *argv[])
  581. {
  582.    int i;
  583.  
  584.    for(i=1;i<argc;i++)
  585.    {
  586.       if(argv[i][0]=='-')
  587.      switch(argv[i][1])
  588.      {
  589.         /*Deactivate title bar filename*/
  590.         case 'n':
  591.         case 'N':
  592.            titleBarName=FALSE;
  593.            break;
  594.  
  595.         /*Deactivate title bar time*/
  596.         case 't':
  597.         case 'T':
  598.            titleBarTime=FALSE;
  599.            break;
  600.  
  601.         /* Read the entire sample into memory before playing */
  602.         case 'm':
  603.         case 'M':
  604.            readAll=TRUE;
  605.            break;
  606.  
  607.         /* Use the left channel */
  608.         case 'l':
  609.         case 'L':
  610.            audioChannel=MONO_LEFT;
  611.            break;
  612.  
  613.         /* Use the right channel */
  614.         case 'r':
  615.         case 'R':
  616.            audioChannel=MONO_RIGHT;
  617.            break;
  618.  
  619.         /*Play a mono sample out of both speakers*/
  620.         case '2':
  621.            bothChan=TRUE;
  622.            break;
  623.  
  624.         /* Switch off the low-pass filter while the sample is playing */
  625.         case 'f':
  626.         case 'F':
  627.            noFilter=TRUE;
  628.            break;
  629.  
  630.         /* Play a sample at a given speed */
  631.         case 's':
  632.         case 'S':
  633.            speed=atol(&argv[i][2]);
  634.            if(speed > 28000)
  635.           speed=0;
  636.            break;
  637.  
  638.         /* The volume at which the sample should be played */
  639.         case 'v':
  640.         case 'V':
  641.            volume=atol(&argv[i][2]);
  642.            if(volume > 64)
  643.           volume=0;
  644.            break;
  645.  
  646.         /* The size of the chip RAM buffers */
  647.         case 'b':
  648.         case 'B':
  649.            bufSize=(atol(&argv[i][2])+1)&(~1);
  650.            if(bufSize==0)
  651.           bufSize=DEF_BUF_SIZE;
  652.            break;
  653.  
  654.         /* Loop the sample */
  655.         case 'o':
  656.         case 'O':
  657.            loop=TRUE;
  658.            break;
  659.  
  660.         case 'w':
  661.         case 'W':
  662.            openTheWdw=FALSE;
  663.            break;
  664.      }
  665.       else if(argv[i][0]=='?')
  666.       {
  667.      /*On-line help*/
  668.      WriteMsg("DSound V1.31 ⌐1991-1994 by Dave Schreiber\n");
  669.      WriteMsg("Usage:\n");
  670.      WriteMsg("  DSound <options> <filename>\n");
  671.      WriteMsg("Where the options are:\n");
  672.      WriteMsg("  -l -- Play the sample using the left speaker\n");
  673.      WriteMsg("  -r -- Play the sample using the right speaker\n");
  674.      WriteMsg("  -2 -- Play the sample using both speakers\n");
  675.      WriteMsg("  -f -- Shut off the low-pass filter\n");
  676.      WriteMsg("  -m -- Load the entire sample into memory\n");
  677.      WriteMsg("  -o -- Play the sample continuously (loop)\n");
  678.      WriteMsg("  -w -- Do not open the DSound window\n");
  679.      WriteMsg("  -n -- Do not show the sample name in the window\n");
  680.      WriteMsg("  -t -- Do not show the sample times in the window\n");
  681.      WriteMsg("  -s<speed> -- Play the sample at the given speed (samples/sec)\n");
  682.      WriteMsg("  -v<volume> -- Play the sample at the given volume (0-64)\n");
  683.      WriteMsg("  -b<bufsize> -- Use a buffer of size <bufsize> (default is 30K)\n");
  684.      exit(0);
  685.       }
  686.       else     /*Otherwise, the argument is a filename */
  687.      strcpy(filename,argv[i]);
  688.    }
  689. }
  690.  
  691. /*Update the sample information in the DSound window's title bar*/
  692. /*This information can included the name of the sample, along with*/
  693. /*its length and amount played (both in seconds)*/
  694. void updateSampleInfo(unsigned int currentPos,unsigned int length,
  695.               unsigned int sampleRate)
  696. {
  697.    unsigned int currentSeconds,currentMinutes,totalSeconds,totalMinutes;
  698.    static char windowTitle[256];
  699.    char tempBuf[4][4];
  700.    static BOOL nameAlreadyDisplayed=FALSE;
  701.  
  702.    /*If the user wants neither the name nor time printed, do nothing*/
  703.    /*Also do nothing if the window isn't open*/
  704.    if((titleBarTime==FALSE && titleBarName==FALSE) || window==NULL)
  705.       return;
  706.  
  707.    /*Return if the user just wanted the name displayed, and it has been*/
  708.    if(titleBarTime==FALSE && nameAlreadyDisplayed==TRUE)
  709.       return;
  710.  
  711.    /*Beginning of the title*/
  712.    strcpy(windowTitle,"DSound V1.31:  ");
  713.  
  714.    /*If the user wants the sample name displayed, put it in the buffer*/
  715.    if(titleBarName)
  716.    {
  717.       nameAlreadyDisplayed=TRUE;
  718.       sprintf(&windowTitle[strlen(windowTitle)],"\"%s\" ",filename);
  719.  
  720.       /*The name has been (or will be shortly) displayed, so don't */
  721.       /*update it again if you don't have to */
  722.       nameAlreadyDisplayed=TRUE;
  723.    }
  724.  
  725.    /*Likewise for the time left and the total time*/
  726.    if(titleBarTime)
  727.    {
  728.       /*Get the total time*/
  729.       totalSeconds=(length)/sampleRate;
  730.       totalMinutes=totalSeconds/60;
  731.       totalSeconds-=totalMinutes*60;
  732.  
  733.       /*Get the current time*/
  734.       currentSeconds=(currentPos)/sampleRate;
  735.       currentMinutes=currentSeconds/60;
  736.       currentSeconds-=currentMinutes*60;
  737.  
  738.       /*Create the string that holds the time, and put it in the*/
  739.       /*title bar buffer*/
  740.       sprintf(&windowTitle[strlen(windowTitle)],"(%s:%s/%s:%s)",
  741.              getDoubleDigit(currentMinutes,tempBuf[0]),
  742.              getDoubleDigit(currentSeconds,tempBuf[1]),
  743.              getDoubleDigit(totalMinutes,tempBuf[2]),
  744.              getDoubleDigit(totalSeconds,tempBuf[3]));
  745.    }
  746.    Forbid();
  747.       /*Make sure that the screen isn't locked (e.g. holding down the*/
  748.       /*RMB will lock the screen), so that DSound will continue to */
  749.       /*play even if it can't update the title bar*/
  750.       if(window->WScreen->LayerInfo.Lock.ss_NestCount==0)
  751.      SetWindowTitles(window,windowTitle,NULL);
  752.    Permit();
  753.  
  754.    return;
  755. }
  756.  
  757. char *getDoubleDigit(unsigned int value,char *buf)
  758. {
  759.    if(value<10)
  760.       sprintf(buf,"0%d",value);
  761.    else
  762.       sprintf(buf,"%d",value);
  763.  
  764.    return(buf);
  765. }
  766.  
  767. /*Switch on the low-pass filter */
  768. void filter_on()
  769. {
  770.    *((char *)0x0bfe001)&=0xFD;
  771. }
  772.  
  773. /*Switch off the low-pass filter*/
  774. void filter_off()
  775. {
  776.    *((char *)0x0bfe001)|=0x02;
  777. }
  778.  
  779. /*Write a message to the CLI*/
  780. void WriteMsg(char *errMsg)
  781. {
  782.    Write(Output(),errMsg,strlen(errMsg));
  783. }
  784.  
  785. /*Take a file handle and that handle's filename, and open that file again*/
  786. /*The position in the second file in set to the position in the first */
  787. /*file (so that the two file handles are essentially identical)*/
  788. /*This requires that the first file was opened in a shared mode, like */
  789. /*MODE_OLDFILE*/
  790. BPTR dupFileHandle(BPTR origFile,char *filename)
  791. {
  792.    BPTR dupFile;
  793.  
  794.    dupFile=Open(filename,MODE_OLDFILE);
  795.  
  796.    if(dupFile==NULL)
  797.       return(NULL);
  798.  
  799.    Seek(dupFile,getPosInFile(origFile),OFFSET_BEGINNING);
  800.    return(dupFile);
  801. }
  802.  
  803. /*Get the current position in a file*/
  804. ULONG getPosInFile(BPTR file)
  805. {
  806.    LONG position;
  807.  
  808.    position=Seek(file,0,OFFSET_CURRENT);
  809.    return((ULONG)position);
  810. }
  811.  
  812. /* Free allocated resources */
  813. void cleanup(int err)
  814. {
  815.    /*If the entire sample was read into memory, this will delete whatever*/
  816.    /*part of the sample still remains in memory*/
  817.    deleteLeft();
  818.    deleteRight();
  819.  
  820.    if(file!=NULL)
  821.       Close(file);
  822.  
  823.    if(window!=NULL)
  824.       CloseWindow(window);
  825.  
  826.    if(titleBarFont!=NULL)
  827.       CloseFont(titleBarFont);
  828.  
  829.    if(GfxBase!=NULL)
  830.       CloseLibrary((struct Library *)GfxBase);
  831.  
  832.    if(IntuitionBase!=NULL)
  833.       CloseLibrary((struct Library *)IntuitionBase);
  834.  
  835.    exit(err);
  836. }
  837.  
  838. #ifdef LATTICE
  839. int CXBRK(void) {return(0);}
  840. int chkabort(void) {return(0);}
  841. #endif
  842.  
  843. /*End of DSound.c*/
  844.  
  845.